import { ElLoading, ElMessageBox, ElMessage, ElNotification } from 'element-plus'
import {
  AxiosRequestConfig,
  AxiosStatic,
  CreateAxiosDefaults,
  AxiosInstance,
  AxiosResponse,
  AxiosRequestHeaders,
  InternalAxiosRequestConfig
} from 'axios'
import defaultSettings from '@/settings'
import { getToken } from '@/utils/auth'
import aesUtils from '@/utils/aes'
import jsEncryptUtils from '@/utils/jsencrypt'
import errorCode from '@/utils/errorCode'
import { useUserStore } from '@/store/modules/user'
import axios from 'axios'

// Anvil扩展配置
export interface AnvilExtentConfig {
  // 对象以Map的形式传输，后台用Map对象接收
  objectAsMap?: boolean
  // 是否加密
  security?: Boolean
  // 不使用默认的加载等待
  noLoading?: boolean
}

// Anvil的请求配置
export interface AnvilAxiosRequestConfig<D = any> extends AxiosRequestConfig<D> {
  headers?: AxiosRequestHeaders
  extCfg?: AnvilExtentConfig
}

export class AnvilAxiosInstance {
  private inst: AxiosInstance
  private requestLoading: any

  constructor(instance: AxiosInstance, loading: any) {
    this.inst = instance
    this.requestLoading = loading
  }

  request(config: AnvilAxiosRequestConfig) {
    this.requestUse(config.extCfg)
    this.responseUse()
    return this.inst.request(config)
  }

  private requestUse(extentConfig?: AnvilExtentConfig) {
    this.inst.interceptors.request.clear()
    this.inst.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // 扩展参数
        const extCfg = extentConfig || {}
        // 是否需要设置 token
        const isToken = config.headers?.isToken === false
        // FormData提交
        if ('FormData' === config.data?.constructor.name) {
          config.headers.setContentType('multipart/form-data')
        }
        if (getToken() && !isToken) {
          if (defaultSettings.isCould === true) {
            config.headers?.set('Authorization', 'Bearer ' + getToken())
          } else {
            // 让每个请求携带自定义token 请根据实际情况自行修改
            config.headers?.set(defaultSettings.tokenName, 'Bearer ' + getToken())
          }
        }

        // 是否加密传输
        if (extCfg && extCfg.security === true) {
          config.headers?.set('security', 'securityData')
          const contentType = (config.headers?.get('Content-Type') ||
            'application/json;charset=UTF-8') as string
          const aesKey = aesUtils.generatekey(16)
          const newData = {
            key: jsEncryptUtils.encrypt(aesKey),
            data: aesUtils.encrypt(JSON.stringify(config.data), aesKey)
          }
          const method: string = config.method || ''

          if (contentType.indexOf('/json') > 0 && method.toLocaleUpperCase() !== 'GET') {
            config['data'] = JSON.stringify(newData)
          } else {
            config['data'] = newData
          }
        }
        // 不启动Loading框
        if (extCfg && extCfg.noLoading !== true) {
          this.requestLoading = ElLoading.service({
            fullscreen: true,
            text: '数据加载中......',
            spinner: 'el-icon-loading',
            background: 'rgba(0, 0, 0, 0.7)'
          })
        }
        return config
      },
      (error: any) => {
        console.log('err' + error)

        if (this.requestLoading) {
          this.requestLoading.close()
        }

        let { message } = error
        if (message == 'Network Error') {
          message = '后端接口连接异常'
        } else if (message.includes('timeout')) {
          message = '系统接口请求超时'
        } else if (message.includes('Request failed with status code')) {
          message = '系统接口' + message.substr(message.length - 3) + '异常'
        }
        ElMessage({
          message: message,
          type: 'error'
        })
        return Promise.reject(error)
      }
    )
  }

  private responseUse() {
    this.inst.interceptors.response.clear()
    this.inst.interceptors.response.use(
      (res: AxiosResponse) => {
        if (this.requestLoading) {
          this.requestLoading.close()
        }

        // 未设置状态码则默认成功状态
        const code = res.data.code || 200
        // 获取错误信息
        // const msg = errorCode[code] || res.data.msg || errorCode['default']
        const msg = res.data.msg || errorCode.get(code) || errorCode.get('default')
        if (code === 401 || code === '401') {
          ElMessageBox.confirm('登录状态已过期，您可以继续留在该页面，或者重新登录', '系统提示', {
            confirmButtonText: '重新登录',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            useUserStore()
              .logout()
              .then(() => {
                location.reload()
              })
          })
        } else if (code === 500 || code === '500') {
          if (defaultSettings.AjaxErrorType == 'MSG') {
            ElMessage.error(msg)
          } else {
            ElMessageBox.confirm(msg, '错误提示', {
              confirmButtonText: '关闭',
              showCancelButton: false,
              closeOnClickModal: false,
              type: 'error'
            })
          }
          return Promise.reject(new Error(msg))
        } else if (code !== 200 && code !== '200') {
          if (defaultSettings.AjaxErrorType == 'MSG') {
            ElNotification.error({
              title: msg
            })
          } else {
            ElMessageBox.confirm(msg, '错误提示', {
              confirmButtonText: '关闭',
              showCancelButton: false,
              closeOnClickModal: false,
              type: 'error'
            })
          }

          return Promise.reject(new Error(msg))
        } else {
          return res.data
        }
      },
      (error: any) => {
        console.log('err' + error)

        if (this.requestLoading) {
          this.requestLoading.close()
        }

        let { message } = error
        if (message == 'Network Error') {
          message = '后端接口连接异常'
        } else if (message.includes('timeout')) {
          message = '系统接口请求超时'
        } else if (message.includes('Request failed with status code')) {
          message = '系统接口' + message.substr(message.length - 3) + '异常'
        }

        if (defaultSettings.AjaxErrorType == 'MSG') {
          ElMessage.error(message)
        } else {
          ElMessageBox.confirm(message, '错误提示', {
            confirmButtonText: '关闭',
            showCancelButton: false,
            closeOnClickModal: false,
            type: 'error'
          })
        }

        return Promise.reject(error)
      }
    )
  }
}

export class AnvilAxiosStatic {
  axios: AxiosStatic

  constructor(axios: AxiosStatic) {
    this.axios = axios
  }

  createAnvil(config?: CreateAxiosDefaults, loading?: any): AnvilAxiosInstance {
    const axiosInstance = this.axios.create(config)
    return new AnvilAxiosInstance(axiosInstance, loading)
  }
}

// 等待框实例
const requestLoading: any = undefined
const anvilAxios: AnvilAxiosStatic = new AnvilAxiosStatic(axios)
// 创建 axios 实例
const service = anvilAxios.createAnvil(
  {
    baseURL: import.meta.env.VITE_APP_BASE_API,
    timeout: 30000,
    headers: { 'Content-Type': 'application/json;charset=utf-8' }
  },
  requestLoading
)

export default service

/**
 * 判断是否包含中文或特殊字符
 * @param {string} e 输入字符串
 * @returns 是否中文或特殊字符
 */
export function checkIsChinese(e: string): Boolean {
  const t = new RegExp('[一-龥]')
  const n = new RegExp(
    "[%--`~!@#$^&*()=|{}':;',\\[\\].<>/?~！@#￥……&*（）——| {}【】‘；：”“'。，、？]"
  )
  return t.test(e) || n.test(e)
}

/**
 *
 * 判断是否包含特殊字符
 * @param {string} e 输入字符串
 * @returns 是否特殊字符
 */
export function checkInSpecialCharacters(e: string): Boolean {
  const t = new RegExp(
    "[%--`~!@#$^&*()=|{}':;',\\[\\].<>/?~！@#￥……&*（）——| {}【】‘；：”“'。，、？]"
  )
  return t.test(e)
}
